import React, {
  useState,
  forwardRef,
  useImperativeHandle,
  useRef,
} from 'react'
import { useTranslation } from 'react-i18next'
import { RiCloseCircleFill } from '@remixicon/react'
import classNames from 'classnames'
import { info } from '@/library/tool-kits/log'
import { bound } from '@/library/tool-kits/bound'
import { isIos } from '@/library/tool-kits/is-device'
import { withNativeProps } from '../../utils/native-props'
import { usePropsValue } from '../../hooks/use-props-value'
import { useIsomorphicLayoutEffect } from '../../hooks/use-isomorphic-layout-effect'
import type {
  InputRef,
  InputProps,
} from './type'

const classPrefix = 'rt-input'

export const Input = forwardRef<InputRef, InputProps>((props, ref) => {
  const {
    autoComplete,
    autoCapitalize, // 用于控制在用户输入/编辑文本输入时是否以及如何自动大写。
    autoCorrect, // 仅 Safari 适用。一个字符串，表示是否在用户编辑该字段时激活自动更正
    autoFocus,
    clearable,
    disabled,
    defaultValue = '',
    enterKeyHint,
    id,
    inputMode, // 对所有元素都有效的全局值，为浏览器提供提示，说明在编辑其内容时要使用的虚拟键盘配置类型
    icon,
    label = '请输入',
    maxLength,
    minLength,
    max,
    min,
    mode = 'default',
    name,
    onClick,
    onClear,
    onChange,
    onFocus,
    onBlur,
    onEnterPress,
    onKeyUp,
    onKeyDown,
    onCompositionStart,
    onCompositionEnd,
    onlyShowClearWhenFocus = false,
    placeholder,
    pattern,
    readOnly,
    role,
    step,
    type,
    value,
  } = props

  const { t: translate } = useTranslation()

  const [actValue, setActValue] = usePropsValue({
    value,
    defaultValue,
    onChange,
  })
  const [hasFocus, setHasFocus] = useState(false)
  const compositionStartRef = useRef(false)
  const nativeInputRef = useRef<HTMLInputElement>(null)

  useImperativeHandle(ref, () => ({
    clear: () => {
      setActValue('')
    },
    focus: () => {
      nativeInputRef.current?.focus()
    },
    blur: () => {
      nativeInputRef.current?.blur()
    },
    get nativeElement() {
      return nativeInputRef.current
    },
  }))

  const handleKeydown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (onEnterPress && (e.code === 'Enter' || e.keyCode === 13)) {
      onEnterPress(e)
    }
    onKeyDown?.(e)
  }

  useIsomorphicLayoutEffect(() => {
    if (!enterKeyHint) return undefined
    nativeInputRef.current?.setAttribute('enterkeyhint', enterKeyHint!)
    return () => {
      nativeInputRef.current?.removeAttribute('enterkeyhint')
    }
  }, [enterKeyHint])

  function checkValue() {
    let nextValue = actValue
    if (type === 'number') {
      const boundValue = nextValue
        && bound(parseFloat(nextValue), min, max).toString()
      // fix the display issue of numbers starting with 0
      if (Number(nextValue) !== Number(boundValue)) {
        nextValue = boundValue
      }
    }
    if (nextValue !== actValue) {
      setActValue(nextValue)
    }
  }

  const shouldShowClear = (() => {
    // 存在自定义图标不显示默认清除图标
    if (icon) return false
    if (!clearable || !actValue || readOnly) return false
    // 在输入框获取焦点时会显示
    if (onlyShowClearWhenFocus) {
      return hasFocus
    }
    return true
  })()

  return withNativeProps(
    props,
    <div
      className={classNames(
        `${classPrefix}`,
        disabled && `${classPrefix}-disabled`,
        mode === 'label' && `${classPrefix}-mode-label`,
      )}
    >
      {
        mode === 'label' && (
          <div className={classNames(
            `${classPrefix}-label`,
            hasFocus && `${classPrefix}-label-active`,
          )}
          >
            {label}
          </div>
        )
      }
      <input
        ref={nativeInputRef}
        className={`${classPrefix}-element`}
        value={actValue}
        id={id}
        placeholder={placeholder}
        disabled={disabled}
        readOnly={readOnly}
        maxLength={maxLength}
        minLength={minLength}
        max={max}
        min={min}
        autoComplete={autoComplete}
        autoFocus={autoFocus}
        pattern={pattern}
        inputMode={inputMode}
        type={type}
        name={name}
        autoCapitalize={autoCapitalize}
        autoCorrect={autoCorrect}
        onKeyDown={handleKeydown}
        onKeyUp={onKeyUp}
        onChange={(e) => {
          setActValue(e.target.value)
        }}
        onFocus={(e) => {
          setHasFocus(true)
          onFocus?.(e)
        }}
        onBlur={(e) => {
          setHasFocus(false)
          checkValue()
          onBlur?.(e)
        }}
        onCompositionStart={(e) => {
          info(
            'Input',
            'Input.onCompositionStart Event Starts',
          )
          compositionStartRef.current = true
          onCompositionStart?.(e)
        }}
        onCompositionEnd={(e) => {
          info(
            'Input',
            'Input.onCompositionStart Event End',
          )
          compositionStartRef.current = false
          onCompositionEnd?.(e)
        }}
        onClick={onClick}
        step={step}
        role={role}
        aria-valuenow={props['aria-valuenow']}
        aria-valuemax={props['aria-valuemax']}
        aria-valuemin={props['aria-valuemin']}
        aria-label={props['aria-label']}
      />
      {shouldShowClear && (
        <div
          className={`${classPrefix}-clear`}
          onMouseDown={(e) => {
            e.preventDefault()
          }}
          onClick={() => {
            setActValue('')
            onClear?.()
            // https://github.com/ant-design/ant-design-mobile/issues/5212
            if (isIos && compositionStartRef.current) {
              compositionStartRef.current = false
              nativeInputRef.current?.blur()
            }
          }}
          aria-label={translate('common.gallery.Input.clear')}
        >
          <RiCloseCircleFill size={18} />
        </div>
      )}
      {icon && (<div className={`${classPrefix}-custom-icon`}>{icon}</div>)}
    </div>,
  )
})
